package com.aysafety.eventmodel.service.integrationWarning.impl;

import com.aysafety.eventmodel.common.DateUtils;
import com.aysafety.eventmodel.dao.MultiParameterIntegratedWarningDao;
import com.aysafety.eventmodel.dao.TreeDao;
import com.aysafety.eventmodel.service.integrationWarning.MultiParameterIntegratedWarningService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

@Service
public class MultiParameterIntegratedWarningServiceImpl implements MultiParameterIntegratedWarningService {

    private Logger logger = LoggerFactory.getLogger(MultiParameterIntegratedWarningServiceImpl.class);


    // 微震预警结果表
    private final static String MICROSEISMWARNING_TABLE = "MicroseismWarning";

    // 液压支架预警结果表
    private final static String HYDRAULICSUPPORTWARNING_TABLE = "HydraulicSupportWarning";

    // 地音预警结果表
    private final static String GEOSOUNDWARNING_TABLE = "GEOSOUNDWARNING";

    // 微震遗传算法结果表
    private final static String MICROSEISMWARNINGSTUDY_TABLE = "MICROSEISMWARNINGSTUDY";

    // 液压支架遗传算法结果表
    private final static String HYDRAULICSUPPORTWARNINGSTUDY_TABLE = "HYDRAULICSUPPORTWARNINGSTUDY";

    // 地音遗传算法结果表
    private final static String GEOSOUNDWARNINGSTUDY_TABLE = "GEOSOUNDWARNINGSTUDY";

    @Autowired
    private TreeDao treeDao;

    @Autowired
    private MultiParameterIntegratedWarningDao multiParameterIntegratedWarningDao;

    @Override
    public void multiParameterIntegratedWarning(String currentTime) throws Exception {
        //[t-1min,t]
        //String startTime = DateUtils.getCurrentMinuteStartTime("yyyy-MM-dd HH:mm:ss", DateUtils.getBeforeMinuteDate(-10, currentTime));
        //String endTime = DateUtils.getCurrentMinuteStartTime("yyyy-MM-dd HH:mm:ss", currentTime);

        String startTime = DateUtils.getCurrentMinuteStartTime("yyyy-MM-dd HH:mm:ss", "2017-05-01 00:00:00");
        String endTime = DateUtils.getCurrentMinuteStartTime("yyyy-MM-dd HH:mm:ss", "2019-05-01 00:00:00");

        long sTime = DateUtils.fomatDateTime(startTime).getTime();
        long eTime = DateUtils.fomatDateTime(endTime).getTime();

        Map<String, Object> treeMap = new HashMap<String, Object>(1);
        //treeMap.put("type", "\'" + "hydraulicSupport" + "\'");
        treeMap.put("entId", "\'" + "xinjiangwudong" + "\'");
        // 树
        List<Map<String, Object>> tree = removeDuplicateWithOrder(treeDao.queryTreeData(treeMap));

        for (Map<String, Object> treeData : tree) {

            String entId = treeData.get("entId").toString();
            //String deviceId = treeData.get("deviceId").toString();
            String tableId = entId + "." + MICROSEISMWARNING_TABLE;
            Map<String, Object> params = queryParameter(tableId, entId, sTime, eTime);
            List<Map<String, Object>> microseismWarningResults = multiParameterIntegratedWarningDao.queryMicroseismWarning(params);
            List<Double> weizhenResult = wList(microseismWarningResults);

            tableId = entId + "." + HYDRAULICSUPPORTWARNING_TABLE;
            params = queryParameter(tableId, entId, sTime, eTime);
            List<Map<String, Object>> supportWarningResults = multiParameterIntegratedWarningDao.queryHydraulicSupportWarning(params);
            List<Double> zhijiaResult = wList(supportWarningResults);


            tableId = entId + "." + GEOSOUNDWARNING_TABLE;
            params = queryParameter(tableId, entId, sTime, eTime);
            List<Map<String, Object>> geosoundWariningResults = multiParameterIntegratedWarningDao.queryGeosoundWarining(params);
            List<Double> diyinResult = wList(geosoundWariningResults);


            List<Double> rs = queryRs(entId);

            // 计算多参量综合预警
            List<Double> ws = computeW(weizhenResult, zhijiaResult, diyinResult, rs.get(0), rs.get(1), rs.get(2));

            String tableId1 = entId + "."+"MULTIPARAMETERWARNING";
            for (int i=0; i<ws.size(); i++) {
                saveMultiParams(String.valueOf(supportWarningResults.get(i).get("datetime")), tableId1, ws.get(i));
            }
        }
    }


    /**
     * 将微震预警结果与支架预警结果进行结合，分析两个系统在2017年3月之后的综合预警结果
     * @param startTime
     * @param endTime
     */
    private void microseismAndHydraulicSupportWarning(String startTime, String endTime) {


    }

    /**
     * 保存多参量综合预警结果到数据库中
     * @param datetime
     * @param tableId
     * @param w
     */
    private void saveMultiParams(String datetime, String tableId, double w) {
        Map<String, Object> multiParams = new HashMap<>();
        multiParams.put("pk", "\'" + datetime + "\'");
        multiParams.put("tableId", tableId);
        multiParams.put("W", w);
        multiParams.put("datetime", Long.parseLong(datetime));
        multiParameterIntegratedWarningDao.saveMultiParamsWarning(multiParams);
    }


    /**
     * 查询微震、液压支架、地音的遗传算法结果R值
     * @return
     */
    private List<Double> queryRs(String entId) {
        List<Double> rs = new ArrayList<>();
        Map<String, Object> params = new HashMap<>();
        params.put("entId", "\'" + entId + "\'");
        params.put("tableId", MICROSEISMWARNINGSTUDY_TABLE);
        //查询微震遗传算法结果R值
        List<Double> weizhenRs = multiParameterIntegratedWarningDao.queryMicroseismWarningStudy(params);
        rs.add(0, weizhenRs.get(0));

        params.put("tableId", HYDRAULICSUPPORTWARNINGSTUDY_TABLE);
        // 查询液压支架遗传算法结果R值
        List<Double> zhijiaRs = multiParameterIntegratedWarningDao.queryHydraulicSupportWarningStudy(params);
        rs.add(1, zhijiaRs.get(0));

        params.put("tableId", GEOSOUNDWARNINGSTUDY_TABLE);
        // 查询地音遗传算法结果R值
        List<Double> diyinRs = multiParameterIntegratedWarningDao.queryGeosoundWariningStudy(params);
        rs.add(2, diyinRs.get(0));

        return rs;
    }


    private List<Double> wList(List<Map<String, Object>> list) {
        List<Double> wlist = new ArrayList<>();
        for (Map<String, Object> map : list) {
            wlist.add((Double) map.get("W"));
        }
        return wlist;
    }

    /**
     * 将微震预警结果和地音预警结果进行结合，分析两个系统在2016年7月1日之后的预警结果
     * @param startTime
     * @param endTime
     */
    private void microseismAndGeosoundWarning(String startTime, String endTime) {

    }

    /**
     * 将微震预警结果和地音预警结果进行结合，分析两个系统在2016年7月1日之后的预警结果
     * @param microseismWarningResults
     * @param geosoundWarningResults
     */
    private void microseismAndGeosoundWarning(List<Map<String, Object>> microseismWarningResults, List<Map<String, Object>> geosoundWarningResults) {

    }

    /**
     * 拼接查表用的查询参数
     * @param tableName
     * @return
     */
    private Map<String, Object> queryParameter(String tableName, String entId, long sTime, long endTime) {
        Map<String, Object> params = new HashMap<>();
        //String entId = treeData.get("entId").toString();
        params.put("entId", entId);
        params.put("tableId", tableName);
        params.put("startTime", sTime);
        params.put("endTime", endTime);
        return params;
    }

    /**
     * 计算多参量综合预警, 因为预警结果是随时间变化的，每时都会产生预警结果，
     * 所以，传入的是一个时间段的预警结果，得到的也是一个时间段的多参量综合预警结果
     *
     * 2017年3月之后，三个系统都有记录
     *
     * @param weizhenResult 微震预警结果
     * @param zhijiaResult 液压支架预警结果
     * @param diyinResult 地音预警结果
     * @param weizhenR 微震R值
     * @param zhijiaR 液压支架R值
     * @param diyinR 地音R值
     * @return 多参量综合预警结果
     */
    private List<Double> computeW(List<Double> weizhenResult, List<Double> zhijiaResult, List<Double> diyinResult,
                            double weizhenR, double zhijiaR, double diyinR) {
        List<Double> result = new ArrayList<>();

        double sumR = weizhenR + zhijiaR + diyinR;

        List<Integer> count0 = new ArrayList<>();
        List<Integer> count1 = new ArrayList<>();
        for (int i = 0; i < zhijiaResult.size(); i++) {
            int maxIndex1 = max(weizhenResult, zhijiaResult, i);
            if (-1 != maxIndex1){
                count0.add(maxIndex1);
            }

            int maxIndex2 = max(diyinResult, zhijiaResult, i);
            if (-1 != maxIndex2) {
                count1.add(maxIndex2);
            }

            for (int j = 0; j < count0.size(); j++) {
                //if (weizhenResult.get(count0.get(j)) > 0.6) {
                    //double temp = weizhenResult.get(count0.get(j)) * weizhenR + zhijiaResult.get(i) * zhijiaR + diyinResult.get(j) * diyinR;
                    double temp = weizhenResult.get(maxIndex1) * weizhenR + zhijiaResult.get(i) * zhijiaR + diyinResult.get(maxIndex2) * diyinR;
                    // 这里用BigDecimal类包装一下，四舍五入取小数点后两位
                    BigDecimal w = new BigDecimal(temp).divide(new BigDecimal(sumR), 2, BigDecimal.ROUND_UP);

                    if (result.size() == i) {
                        result.add(i, w.doubleValue());
                    } else {
                        result.set(i, w.doubleValue());
                    }

                //}
            }
        }
        return result;
    }


    private int max(List<Double> args1, List<Double>args2, int index) {
        int maxIndex = -1;
        for (int i = 0; i < args1.size(); i++) {
            if (args1.get(i) <= args2.get(index) + 0.0001) {
                maxIndex = i;
            }
        }
        return maxIndex;
    }

    // 删除ArrayList中重复元素，保持顺序
    private static List<Map<String, Object>> removeDuplicateWithOrder(List<Map<String, Object>> list) {
        Set<Map<String, Object>> set = new HashSet<Map<String, Object>>();
        List<Map<String, Object>> newList = new ArrayList<Map<String, Object>>();
        for (int i = 0; i < list.size(); i++) {
            Map<String, Object> map = new HashMap<String, Object>(2);
            map.put("entId", list.get(i).get("entId"));
            map.put("deviceId", list.get(i).get("deviceId"));
            if (set.add(map)) {
                newList.add(map);
            }
        }
        return newList;
    }
}
